package com.xu.cloud.common.util;

/**
 * 十进制数字转换任意进制数工具类, 最大支持62进制
 *
 * @author xuguan
 * @since 2024/3/4
 */
public class NumberConvertUtil {
    /**
     * 2进制
     */
    public static final int BASE_2 = 2;
    /**
     * 8进制
     */
    public static final int BASE_8 = 8;
    /**
     * 16进制
     */
    public static final int BASE_16 = 16;
    /**
     * 32进制
     */
    public static final int BASE_32 = 32;
    /**
     * 62进制
     */
    public static final int BASE_62 = 62;

    /**
     * 在进制表示中的字符集合，0-Z分别用于表示最大为62进制的符号表示
     */
    private static final char[] digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};

    /**
     * 十进制数字转换为指定进制数
     *
     * @param num  十进制数字
     * @param base 需要转换的进制
     * @return 转换后的进制字符串
     */
    public static String numToBase(long num, int base) {
        checkNumToBase(num, base);
        StringBuilder sb = new StringBuilder();

        // 获取余数
        while (num > 0) {
            int idx = (int) (num % base);
            sb.append(digits[idx]);
            num /= base;
        }

        // 得到的所有余数逆序排列就是最终的进制数
        return sb.reverse().toString();
    }

    /**
     * 指定进制数字符串转换为十进制数字
     *
     * @param baseStr 进制字符串
     * @param base    进制字符串的进制数
     * @return 转换后的十进制数字
     */
    public static long baseToNum(String baseStr, int base) {
        checkBaseStrToNum(baseStr, base);
        // 转换后的十进制数
        long num = 0;
        // 进制位上所代表的十进制数
        long digitNum = 1;
        final char[] baseCharArr = baseStr.toCharArray();
        // 从右往左遍历
        for (int i = baseCharArr.length - 1; i >= 0; i--) {
            num += getDigitsInt(baseCharArr[i]) * digitNum;
            digitNum *= base;
        }
        return num;
    }

    /**
     * 进制字符所代表的十进制数
     *
     * @param ch 进制字符
     * @return 十进制数
     */
    private static int getDigitsInt(char ch) {
        for (int i = 0; i < digits.length; i++) {
            if (digits[i] == ch) {
                return i;
            }
        }
        throw new IllegalArgumentException("illegal digit char");
    }

    private static void checkNumToBase(long num, int base) {
        if (num < 0) {
            throw new IllegalArgumentException("negative numbers are not supported");
        }
        if (base <= 0) {
            throw new IllegalArgumentException("the base number must be greater than 0");
        }
        if (base > 62) {
            throw new IllegalArgumentException("the maximum of base number is 62");
        }
    }

    private static void checkBaseStrToNum(String baseStr, int base) {
        if (baseStr == null || "".equals(baseStr.trim())) {
            throw new IllegalArgumentException("illegal base string");
        }
        if (base <= 0) {
            throw new IllegalArgumentException("the base number must be greater than 0");
        }
        if (base > 62) {
            throw new IllegalArgumentException("the maximum of base number is 62");
        }
    }
}
